import './index.css'
import * as THREE from 'three'
import {
    OrbitControls
} from 'three/examples/jsm/Addons.js'
import * as dat from 'dat.gui'

/**
 * Scene
 */
const scene = new THREE.Scene()

/**
 * Textures
 */
// door
const textureLoader = new THREE.TextureLoader()
const doorColorTexture = textureLoader.load('../assets/textures/door/color.jpg')
const doorAlphaTexture = textureLoader.load('../assets/textures/door/alpha.jpg')
const doorAmbientOcclusionTexture = textureLoader.load('../assets/textures/door/ambientOcclusion.jpg')
const doorHeightTexture = textureLoader.load('../assets/textures/door/height.jpg')
const doorMetalnessTexture = textureLoader.load('../assets/textures/door/metalness.jpg')
const doorRoughnessTexture = textureLoader.load('../assets/textures/door/roughness.jpg')
const doorNormalTexture = textureLoader.load('../assets/textures/door/normal.jpg')

// brick
const brickColorTexture = textureLoader.load('../assets/textures/brick/baseColor.jpg')
const brickAmbintOcclusionTexture = textureLoader.load('../assets/textures/brick/ambientOcclusion.jpg')
const brickHeightTexture = textureLoader.load('../assets/textures/brick/height.jpg')
const brickNormalTexture = textureLoader.load('../assets/textures/brick/normal.jpg')
const brickRoughnessTexture = textureLoader.load('../assets/textures/brick/roughness.jpg')


brickColorTexture.repeat.set(3, 3)
brickAmbintOcclusionTexture.repeat.set(3, 3)
brickHeightTexture.repeat.set(3, 3)
brickNormalTexture.repeat.set(3, 3)
brickRoughnessTexture.repeat.set(3, 3)

brickColorTexture.wrapS = THREE.RepeatWrapping
brickColorTexture.wrapT = THREE.RepeatWrapping
brickAmbintOcclusionTexture.wrapS = THREE.RepeatWrapping
brickAmbintOcclusionTexture.wrapT = THREE.RepeatWrapping
brickHeightTexture.wrapS = THREE.RepeatWrapping
brickHeightTexture.wrapT = THREE.RepeatWrapping
brickNormalTexture.wrapS = THREE.RepeatWrapping
brickNormalTexture.wrapT = THREE.RepeatWrapping
brickRoughnessTexture.wrapS = THREE.RepeatWrapping
brickRoughnessTexture.wrapT = THREE.RepeatWrapping


//floor
const floorColorTexture = textureLoader.load('../assets/textures/floor/baseColor.jpg')
const floorAmbientOcclusionTexture = textureLoader.load(
    '../assets/textures/floor/ambientOcclusion.jpg',
)
const floorHeightTexture = textureLoader.load('../assets/textures/floor/height.png')
const floorNormalTexture = textureLoader.load('../assets/textures/floor/normal.jpg')
const floorRoughnessTexture = textureLoader.load('../assets/textures/door2/roughness.jpg')


/**
 * Floor
 */
const material = new THREE.MeshStandardMaterial({
    side: THREE.DoubleSide,
    map: floorColorTexture,
    aoMap: floorAmbientOcclusionTexture,
    displacementMap: floorHeightTexture,
    displacementScale: 0.08,
    normalMap: floorNormalTexture,
    roughnessMap: floorRoughnessTexture
})
floorColorTexture.repeat.set(5, 5)
floorAmbientOcclusionTexture.repeat.set(5, 5)
floorHeightTexture.repeat.set(5, 5)
floorNormalTexture.repeat.set(5, 5)
floorRoughnessTexture.repeat.set(5, 5)

floorColorTexture.wrapS = THREE.RepeatWrapping
floorColorTexture.wrapT = THREE.RepeatWrapping
floorAmbientOcclusionTexture.wrapS = THREE.RepeatWrapping
floorAmbientOcclusionTexture.wrapT = THREE.RepeatWrapping
floorHeightTexture.wrapS = THREE.RepeatWrapping
floorHeightTexture.wrapT = THREE.RepeatWrapping
floorNormalTexture.wrapS = THREE.RepeatWrapping
floorNormalTexture.wrapT = THREE.RepeatWrapping
floorRoughnessTexture.wrapS = THREE.RepeatWrapping
floorRoughnessTexture.wrapT = THREE.RepeatWrapping

const plane = new THREE.Mesh(new THREE.PlaneGeometry(20, 20, 200, 200), material)
plane.rotation.set(-Math.PI / 2, 0, 0)
plane.position.set(0, 0, 0)
scene.add(plane)

/**
 * House
 */
const house = new THREE.Group()
scene.add(house)

//walls
const walls = new THREE.Mesh(
    new THREE.BoxGeometry(4, 3, 4),
    new THREE.MeshStandardMaterial({
        map: brickColorTexture,
        aoMap: brickAmbintOcclusionTexture,
        normalMap: brickNormalTexture,
        displacementMap: brickHeightTexture,
        roughnessMap: brickRoughnessTexture
    })
)
walls.position.y = 1.5
house.add(walls)

//roof
const roof = new THREE.Mesh(
    new THREE.ConeGeometry(3.25, 1, 4),
    new THREE.MeshStandardMaterial({
        color: '#b35f45'
    })
)
roof.position.y = 1 / 2 + 3
roof.rotation.y = Math.PI * 0.25
house.add(roof)

// door
const door = new THREE.Mesh(
    new THREE.PlaneGeometry(2, 2, 100, 100),
    new THREE.MeshStandardMaterial({
        map: doorColorTexture,
        aoMap: doorAmbientOcclusionTexture,
        transparent: true,
        alphaMap: doorAlphaTexture,
        normalMap: doorNormalTexture,
        roughnessMap: doorRoughnessTexture,
        metalnessMap: doorMetalnessTexture,
        displacementMap: doorHeightTexture,
        displacementScale: 0.08
    })
)
door.geometry.setAttribute(
    'uv2',
    new THREE.Float32BufferAttribute(door.geometry.attributes.uv.array, 2),
)
door.position.y = 1
door.position.z = 2.01
house.add(door)


// Bushes
const bushGeometry = new THREE.SphereGeometry(1, 16, 16)
const sphereMaterial = new THREE.MeshStandardMaterial({
    color:'green',
    roughness:0.8
})
const bush = new THREE.Mesh(bushGeometry, sphereMaterial)
const bush1 = bush.clone()
bush1.scale.set(0.5, 0.5, 0.5)
bush1.position.set(-1, 0.3, 3)
scene.add(bush1)
const bush2 = bush.clone()
bush2.scale.set(0.5, 0.5, 0.5)
bush2.position.set(1, 0.3, 3)
scene.add(bush2)
const bush3 = bush.clone()
bush3.scale.set(0.25, 0.25, 0.25)
bush3.position.set(-1.75, 0.3, 3)
scene.add(bush3)
const bush4 = bush.clone()
bush4.scale.set(0.25, 0.25, 0.25)
bush4.position.set(1.75, 0.3, 3)
scene.add(bush4)


// graves
const graves = new THREE.Group()
scene.add(graves)

const graveGeometry = new THREE.BoxGeometry(0.6, 0.8, 0.2)
const graveMaterial = new THREE.MeshStandardMaterial({
    color: '#b2b6b1',
})

for (let i = 0; i < 50; i++) {
    const grave = new THREE.Mesh(graveGeometry, graveMaterial)
    const angle = Math.random() * Math.PI * 2
    const radius = Math.random() * 6 + 4
    const x = Math.cos(angle) * radius
    const z = Math.sin(angle) * radius
    grave.position.set(x, 0.3, z)

    grave.rotation.y = (Math.random() - 0.5) * 0.4
    grave.rotation.z = (Math.random() - 0.5) * 0.4

    grave.castShadow = true
    scene.add(grave)
}


/**
 * Ghosts
 */
const ghost1 = new THREE.PointLight('#ff00ff', 2, 3)
scene.add(ghost1)

const ghost2 = new THREE.PointLight('#00ffff', 2, 3)
scene.add(ghost2)

const ghost3 = new THREE.PointLight('#ffff00', 2, 3)
scene.add(ghost3)



/**
 * Lights
 */
const ambientLight = new THREE.AmbientLight('#ffffff', 0.12)
scene.add(ambientLight)

const directionalLight = new THREE.DirectionalLight('#ffffaa', 0.12)
directionalLight.position.set(1, 0.75, 0)
scene.add(directionalLight)


const doorLight = new THREE.PointLight('#ff7d46', 1, 7)
doorLight.position.set(0, 2, 3)
scene.add(doorLight)


/**
 * Fog
 */
const fog = new THREE.Fog('#262837', 1, 15)
scene.fog = fog

/**
 * Size
 */
const Size = {
    width: window.innerWidth,
    height: window.innerHeight
}

/**
 * Camera
 */
const camera = new THREE.PerspectiveCamera(75, Size.width / Size.height, 0.1, 100)
camera.position.set(7, 1.8, 8)

/**
 * Renderer
 */
const canvas = document.querySelector('canvas.webgl')
const renderer = new THREE.WebGLRenderer({
    canvas
})

renderer.setClearColor('#262837')
// shadowMap
renderer.shadowMap.enabled = true
renderer.setSize(Size.width, Size.height)


/**
 * OrbitControls
 */
const orbitControls = new OrbitControls(camera, canvas)

/**
 * Debug
 */
const gui = new dat.GUI()
const cameraFolder = gui.addFolder('camera')
cameraFolder.add(camera.position, 'x', -20, 20, 0.001)
cameraFolder.add(camera.position, 'y', -20, 20, 0.001)
cameraFolder.add(camera.position, 'z', -20, 20, 0.001)



/**
 * Shadow
 */
directionalLight.castShadow  = true
doorLight.castShadow = true
ghost1.castShadow = true
ghost2.castShadow = true
ghost3.castShadow = true


walls.castShadow = true
bush1.castShadow = true
bush2.castShadow = true
bush3.castShadow = true
bush4.castShadow = true

plane.receiveShadow = true



/**
 * Update
 */
const clock = new THREE.Clock()
const tick = () => {
    const elapsedTime = clock.getElapsedTime()
    console.log(elapsedTime)
    // Ghost
    const ghost1Angle = elapsedTime *0.5
    ghost1.position.x = Math.cos(ghost1Angle) * 4
    ghost1.position.z = Math.sin(ghost1Angle) * 4
    ghost1.position.y = Math.sin(ghost1Angle * 3)


    const ghost2Angle = -elapsedTime * 0.32
    ghost2.position.x = Math.cos(ghost2Angle) * 5
    ghost2.position.z = Math.sin(ghost2Angle) * 5
    ghost2.position.y = Math.sin(elapsedTime * 4) + Math.sin(elapsedTime * 2.5)

    const ghost3Angle = -elapsedTime * 0.18
    ghost3.position.x = Math.cos(ghost3Angle) * (7 + Math.sin(elapsedTime * 0.32))
    ghost3.position.z = Math.sin(ghost3Angle) * (7 + Math.sin(elapsedTime * 0.5))
    ghost3.position.y = Math.sin(elapsedTime * 4) + Math.sin(elapsedTime * 2.5)


    renderer.render(scene, camera)
    orbitControls.update()
    requestAnimationFrame(tick)
}


tick()